package ivr

import (
	"dmsv/models"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
)

const (
	NodeTypeStart         = "startNode"
	NodeTypeGetKey        = "keyNode"
	NodeTypePlay          = "audioNode"
	NodeTypeDtmf          = "numberReceivingNode"
	NodeTypeJudge         = "judgmentNode"
	NodeTypeApi           = "interfaceNode"
	NodeTypeTransferWait  = "transfer"
	NodeTypeService       = "toServiceNode"
	NodeTypeQueue         = "toQueueNode"
	NodeTypeToNumber      = "toNumberNode"
	NodeTypeEnd           = "endNode"
	NodeTypeErrKey        = "wrongkey"
	NodeTypeTimeOut       = "timeOut"
	NodeTypeLeaveMsg      = "leave"
	NodeTypePlayServiceId = "playServiceId" //播放坐席Id
)

type Handle struct {
	appId        string
	manageId     int64
	normalPos    string  //普通节点指针
	specialPos   string  //特殊节点指针
	traceList    []*Node //轨迹跟踪
	specialNode  []Node
	nodeMap      map[string]*Node
	neighbourMap map[string]*[]neighbour
}

func (h *Handle) IsActive() bool {
	return h.appId != ""
}

func (h *Handle) AppId() string {

	return h.appId
}

func (h *Handle) StartIvr() (Node, error) {

	//h.traceList = append(h.traceList, h.nodeMap[h.normalPos])
	node, ok := h.nodeMap[h.normalPos]
	if !ok {
		logs.Error("appId:%v,ivrId:%v,未初始化;初始节点:%v", h.appId, h.manageId, h.normalPos)
		return Node{}, fmt.Errorf("notInit")
	}
	return *node, nil
}

func checkNode(node *Node) bool {

	switch node.NodeType {

	case NodeTypeQueue:
		if node.ToQueue == 0 {
			return false
		}
	case NodeTypeService:
		if len(node.ToService) == 0 {
			return false
		}
	case NodeTypeToNumber:
		if len(node.ToNumber) == 0 {
			return false
		}

	default:
		if len(node.Play) == 0 {
			return false
		}
	}
	return true
}

func (h *Handle) loadFromModel(manageId int64) error {

	//从数据库中加载节点表数据
	for count := 0; ; count++ {

		nodes, err := models.LoadIvrNodes(manageId, count)
		if err == nil {
			for _, node := range nodes {
				n := &Node{
					Id:        node.Id,
					NodeId:    node.NodeId,
					NodeType:  node.NodeType,
					Name:      node.Name,
					GetKey:    node.GetKey,
					ToNumber:  node.Transfer,
					ToQueue:   node.ToQueue,
					ToService: node.ToService,
				}

				if node.FileId > 0 {
					n.Play = models.GetFilePath(node.FileId)
				}

				h.nodeMap[n.NodeId] = n

				if n.NodeType == NodeTypeStart {
					h.normalPos = n.NodeId
				}
				/*
						if checkNode(n) {
							return fmt.Errorf("ivrId [%v] 初始化失败:%v 节点:%v-%v :关键信息缺失 %v.",
								manageId, n.Name, n.NodeId, n)
						}

					logs.Debug("流程Id:%v 加载新节点:%v %v-%v 类型:%v,放音文件::%v.",
						h.manageId, n.Id, n.NodeId, n.Name, n.NodeType, n.Play)

				*/
			}
		} else {
			if err.Error() == "EOF" {
				logs.Debug("流程Id:%v 加载新节点完成.", h.manageId)
			} else {
				logs.Debug("流程Id:%v 加载新节点失败:%v", h.manageId, err)
			}

			break
		}
	}

	//从数据库中加载邻接数据
	for count := 0; ; count++ {

		relations, err := models.LoadIvrNodesNeighbour(manageId, count)
		if err == nil {
			//创建邻接表
			for _, r := range relations {

				if len(r.Child) == 0 {
					continue
				}

				n := neighbour{
					key:   r.Key,
					child: h.nodeMap[r.Child],
				}
				//logs.Debug("节点:%v-%v,添加子节点:%v:%v...", r.Id, r.Node, r.Child, n.child)

				neihbours, ok := h.neighbourMap[r.Node]
				if !ok {
					//不存在 则新建
					newNeihbours := make([]neighbour, 0)
					neihbours = &newNeihbours

					h.neighbourMap[r.Node] = neihbours
				}
				//logs.Debug("节点:%v-%v 新增子节点:%v-%v", r.Id, r.Node, n.child.Id, n.child.Name)
				*neihbours = append(*neihbours, n)
			}
		} else {
			break
		}
	}
	return nil
}

func (h *Handle) TimeOut() *Node {

	for _, node := range h.specialNode {
		//超时语音
		if node.NodeType == NodeTypeTimeOut {
			return &node
		}
	}

	return nil
}

func (h *Handle) MoveToNext(sessionId, key string) *Node {

	logs.Info("%v 当前节点:%v .find next node with key:[ %v ]", sessionId, h.normalPos, key)

	//根据按键跳转,找到兜底跳转的节点
	var lastChance *Node
	if nbs, ok := h.neighbourMap[h.normalPos]; ok {

		for _, nb := range *nbs {
			if nb.key == key {

				//满足该情况,则认为是兜底节点
				if key == "" && h.normalPos == nb.child.NodeId {
					//兜底节点计次
					nb.child.Count++
				} else {
					//重新计次
					nb.child.Count = 0
				}

				//更新当前节点游标
				h.normalPos = nb.child.NodeId

				logs.Debug("%v 匹配节点 :%v,count:%v", sessionId, nb.child.Name, nb.child.Count)
				//返回节点
				return nb.child
			}

			//找到兜底跳转的节点
			if nb.key == "" {
				lastChance = nb.child
			}
		}
	} else {
		logs.Error("[%v] 节点[%v] 无子节点.", sessionId, h.normalPos)
	}

	//兜底跳转
	if lastChance != nil {
		logs.Debug("%v 无匹配节点，使用兜底节点:%v", sessionId, lastChance.Name)

		h.normalPos = lastChance.NodeId
		return lastChance
	}

	//按键错误节点
	for _, node := range h.specialNode {
		if node.NodeType == NodeTypeErrKey {

			logs.Debug("%v key is invalid，return key wrong node", sessionId)
			h.specialPos = node.NodeId
			return &node
		}
	}

	return nil
}

type ivrDebugKey struct {
	Key    string `json:"key"`
	NextId string `json:"nextId"`
}

type ivrDebugNode struct {
	parent   *ivrDebugNode
	Id       string          `json:"id"`
	ManageId int64           `json:"manageId"`
	Name     string          `json:"name"`
	NodeType string          `json:"nodeType"`
	NextId   []ivrDebugKey   `json:"keyList"`
	KeyList  []*ivrDebugNode `json:"children"`
}

func (h *Handle) debugMakeNode(nodeId string) ivrDebugNode {

	memNode, ok := h.nodeMap[nodeId]
	if !ok {
		logs.Error("管理节点:%v 中,不存在节点 [%v]", h.manageId, nodeId)
		return ivrDebugNode{}
	}

	return ivrDebugNode{
		Id:       memNode.NodeId,
		ManageId: h.manageId,
		Name:     memNode.Name,
		NodeType: memNode.NodeType,
	}
}

func (h *Handle) detectUsed(node *ivrDebugNode, id string) bool {

	if node.Id == id {
		return true
	}

	if node.parent == nil {
		return false
	}

	if len(node.parent.KeyList) > 1 {
		for _, child := range node.KeyList {
			if child.Id == id {
				return true
			}
		}
	}

	return h.detectUsed(node.parent, id)
}

func (h *Handle) debugGetChild(node *ivrDebugNode) *ivrDebugNode {

	children, ok := h.neighbourMap[node.Id]
	if !ok {
		logs.Error("流程Id:%v ,节点 %v 无子节点", h.manageId, node.Id)
		return node
	}

	keyList := make([]ivrDebugKey, 0)
	for _, c := range *children {

		keyList = append(keyList, ivrDebugKey{
			Key:    c.key,
			NextId: c.child.NodeId,
		})

		logs.Info("流程Id:%v ,节点 %v-%v 添加子节点Id:%v", h.manageId, node.Id, node.Name, c.child.Id)
	}
	node.NextId = keyList

	for _, child := range *children {

		if h.detectUsed(node, child.child.NodeId) {
			continue
		}

		ch := &ivrDebugNode{
			Id:       child.child.NodeId,
			parent:   node,
			ManageId: h.manageId,
			Name:     child.child.Name,
			NodeType: child.child.NodeType,
		}

		ch = h.debugGetChild(ch)

		node.KeyList = append(node.KeyList, ch)
	}

	return node
}

func (h *Handle) DebugPrint() {

	if len(h.nodeMap) == 0 || len(h.neighbourMap) == 0 {
		logs.Debug("[%v] 无ivr节点", h.appId)
		return
	}

	for _, node := range h.nodeMap {

		value := ""
		switch node.NodeType {
		case NodeTypeService:
			value = node.ToService
		case NodeTypeQueue:
			value = fmt.Sprintf("%d", node.ToQueue)
		case NodeTypeToNumber:
			value = node.ToNumber
		default:
			value = node.Play
		}

		logs.Debug("nodeId:%-16s,节点名称:%-18v,节点类型:%-16v,内容:%-v.",
			node.NodeId, node.Name, node.NodeType, value)
	}

	for key, relation := range h.neighbourMap {

		logs.Debug("节点:%v,子节点个数:%v", key, len(*relation))
		for _, node := range *relation {
			logs.Debug("子节点key:[%2v], nodeId:%-16v, 节点名称:%-16v, 节点类型:%-16v", node.key,
				node.child.Name, node.child.Name, node.child.NodeType)
		}
	}
}

func InitHandle(appId string, manageId int64) *Handle {

	handle := &Handle{
		appId:        appId,
		manageId:     manageId,
		traceList:    make([]*Node, 0),
		nodeMap:      make(map[string]*Node),
		neighbourMap: make(map[string]*[]neighbour),
	}

	err := handle.loadFromModel(manageId)
	if err != nil {
		logs.Debug("初始化 ivr流程 [%v]失败:%v . ", manageId, err)
		return nil
	}
	logs.Debug("初始化:[%v]-ivr流程 [%v] 成功. ", appId, manageId)

	handle.DebugPrint()

	return handle
}
